/**
 * 
 */
package qy.qyalgotrader.technical;

import com.google.common.math.DoubleMath;

import it.unimi.dsi.fastutil.doubles.DoubleList;
import qy.jalgotrade.dataseries.SequenceDataSeries;
import qy.jalgotrade.technical.EventBasedFilter;
import qy.jalgotrade.technical.EventWindow;
import qy.jalgotrade.utils.CommonUtils;

/**
 * This filter calculates efficiency ratio over another dataseries.
 * 
 * @author qy
 *
 */
public class EfficiencyRatio extends EventBasedFilter<Double> {

	/**
	 * 
	 * @author c-geo
	 *
	 */
	private class EffiRatioEventWindow extends EventWindow<Double> {

		/**
		 * 
		 * @param windowSize
		 */
		public EffiRatioEventWindow(int windowSize) {

			super(windowSize, Double.class);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see qy.jalgotrade.technical.EventBasedFilter.EventWindow#getValue()
		 */
		@Override
		public Double getValue() {

			double ret = Double.NaN;
			if (windowFull()) {
				DoubleList values = (DoubleList) getValues();
				if (values.size() > 0) {
					double di = values.getDouble(values.size() - 1) - values.getDouble(0);
					double vola = 0;
					for (int i = 0; i < values.size(); i++) {
						if (i - 1 < 0) {
							vola += 0;
						} else {
							vola += Math.abs(values.getDouble(i) - values.getDouble(i - 1));
						}
					}
					ret = !DoubleMath.fuzzyEquals(vola, 0.0, CommonUtils.FUZZY_EQUAL_TOLERANCE_MATH)
							? Math.abs(di / vola)
							: Double.NaN;
				}
			}
			return ret;
		}
	}

	/**
	 * 
	 * @param dataSeries The DataSeries instance being filtered.
	 * @param windowSize
	 * @throws Exception
	 */
	public EfficiencyRatio(SequenceDataSeries<Double> dataSeries, int windowSize) throws Exception {

		this(dataSeries, windowSize, 0);
	}

	/**
	 * 
	 * @param dataSeries The DataSeries instance being filtered.
	 * @param windowSize
	 * @param maxLen     The maximum number of values to hold. Once a bounded length is full, when new
	 *                   items are added, a corresponding number of items are discarded from the
	 *                   opposite end. If None then dataseries.DEFAULT_MAX_LEN is used.
	 * @throws Exception
	 */
	public EfficiencyRatio(SequenceDataSeries<Double> dataSeries, int windowSize, int maxLen) throws Exception {

		super(maxLen);
		EffiRatioEventWindow win = new EffiRatioEventWindow(windowSize);
		_init(dataSeries, win);
	}
}
